package com.lotso.web.module.batch.listener;

import com.alibaba.fastjson.JSON;
import com.lotso.web.common.utils.DateUtil;
import com.lotso.web.module.batch.entity.BatchSchedule;
import com.lotso.web.module.batch.model.ScheduleStatus;
import com.lotso.web.module.batch.service.impl.BatchScheduleServiceImpl;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.listeners.JobListenerSupport;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Objects;

/**
 * ClassName: CusJobListener
 * Description:
 * Date: 2018/9/10 13:13 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class CustomGlobalJobListener extends JobListenerSupport {

    @Autowired
    private BatchScheduleServiceImpl batchScheduleService;

    @Override
    public String getName() {
        return this.getClass().getName();
    }

    /**
     * Scheduler 在 JobDetail 将要被执行时调用这个方法。
     *
     * @param context
     */
    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        String str = (String) context.getMergedJobDataMap().get(BatchSchedule.SCHEDULE_KEY);
        BatchSchedule scheduleJob = JSON.parseObject(str, BatchSchedule.class);

        getLog().debug("计划 {} ： ~~~ 【RUNNING】 更新正在运行中状态 ~~~ ", scheduleJob.toString());
        this.insertStatus(scheduleJob, ScheduleStatus.RUNNING, false);
    }


    /**
     * Scheduler 在 JobDetail 即将被执行，但又被 TriggerListener 否决了时调用这个方法
     *
     * @param context
     */
    @Override
    public void jobExecutionVetoed(JobExecutionContext context) {
    }

    /**
     * Scheduler 在 JobDetail 被执行之后调用这个方法
     *
     * @param context
     * @param jobException
     */
    @Override
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        String str = (String) context.getMergedJobDataMap().get(BatchSchedule.SCHEDULE_KEY);
        BatchSchedule scheduleJob = JSON.parseObject(str, BatchSchedule.class);

        getLog().debug("计划 {} ： ~~~ 【COMPLETE | ERROR】 更新已经结束状态 ~~~ ", scheduleJob.toString());
        this.insertStatus(scheduleJob, jobException);

        // 唤醒子任务
        batchScheduleService.notifyChildren(scheduleJob);
    }

    /**
     * 更新计划状态
     *
     * @param scheduleJob
     * @param jobException
     * @return
     */
    private boolean insertStatus(BatchSchedule scheduleJob, JobExecutionException jobException) {
        return Objects.isNull(jobException) ? insertStatus(scheduleJob, ScheduleStatus.COMPLETE, true) : insertError(scheduleJob, jobException);
    }


    /**
     * 更新计划状态为异常
     * TODO 重跑策略以及预警通知等
     *
     * @param jobException
     * @param scheduleJob
     * @return
     */
    private boolean insertError(BatchSchedule scheduleJob, JobExecutionException jobException) {
        getLog().error("计划 {}：【ERROR】 {}", scheduleJob.toString(), jobException.getMessage());
        return this.insertStatus(scheduleJob, ScheduleStatus.ERROR, true);

        // jobException.setUnscheduleAllTriggers(true); // 立即停止所有相关这个任务的触发器trigger，从而避免再次运行 job
        // jobException.setRefireImmediately(true); // 立即重新执行（ this job will refire immediately）
    }

    /**
     * 更新计划状态
     *
     * @param scheduleJob
     * @return
     */
    private boolean insertStatus(BatchSchedule scheduleJob, int status, boolean executed) {
        BatchSchedule schedule = new BatchSchedule();
        schedule.setId(scheduleJob.getId());
        schedule.setStatus(status);
        schedule.setStartDate(DateUtil.now());
        schedule.setUpdateDate(DateUtil.now());
        if (executed) {
            schedule.setEndDate(DateUtil.now());
        }
        return batchScheduleService.updateById(schedule);
    }


}
